#ifndef GLOBALS_HH_
# define GLOBALS_HH_
# include <QtCore>
# include <QtXml>
# include <stdint.h>

/// \brief Nem használt függvényparaméter jelezhető vele, így nem okoz warning-ot.
# define DONTCARE(VAR) ((void)(VAR));

/**
 * \brief QSharedPointer osztály typedef-elhető vele.
 * \param TYPE A típus, amire a pointer mutat.
 */
# define QSP(TYPE) typedef QSharedPointer< TYPE > sp##TYPE

/**
 * \brief QWeakPointer osztály typedef-elhető vele.
 * \param TYPE A típus, amire a pointer mutat.
 */
# define QWP(TYPE) typedef QWeakPointer< TYPE > wp##TYPE

/**
 * \brief Sima pointer typedef-elehetó vele.
 * \param TYPE A típus, amire a pointer mutat.
 *
 * Sok értelme nincs, shared és weak pointerek mellett jobban néz ki.
 */
# define P(TYPE) typedef TYPE* p##TYPE

#define GETTER(CLASS, TYPE, FIELD)      \
    TYPE CLASS::get_##FIELD() const {   \
        return FIELD;                   \
    }                                   \

/**
 * \brief Szinkronizált mező lekérdező metódus definíció.
 * \param CLASS Az osztály, aminek a metódusa.
 * \param TYPE  A lekérdezhető mező típusa.
 * \param FIELD A lekérdezhetó mező neve.
 */
#define SYNC_GETTER(CLASS, TYPE, FIELD) \
    TYPE CLASS::get_##FIELD() const {   \
        QMutexLocker locker(&lock);     \
        TYPE result = FIELD;            \
        return result;                  \
    }                                   \

#define SYNC_SETTER(CLASS, TYPE, FIELD)     \
    void CLASS::set_##FIELD(TYPE value) {   \
        QMutexLocker locker(&lock);         \
        FIELD = value;                      \
    }                                       \

#define WP_GETTER(CLASS, TYPE, FIELD)       \
    sp##TYPE CLASS::get_##FIELD() const {   \
        return FIELD.toStrongRef();         \
    }                                       \

/**
 * \brief Szinkronizált weak pointer mező lekérdező metódus definíció.
 * \param CLASS Az osztály, aminek a metódusa.
 * \param TYPE  A lekérdezhető mező típusa (wpFoo esetén Foo).
 * \param FIELD A lekérdezhetó mező neve.
 */
#define SYNC_WP_GETTER(CLASS, TYPE, FIELD)      \
    sp##TYPE CLASS::get_##FIELD() const {       \
        QMutexLocker locker(&lock);             \
        sp##TYPE result = FIELD.toStrongRef();  \
        return result;                          \
    }                                           \

#define SYNC_ADDER(CLASS, TYPE, FIELD)      \
    void CLASS::add_##FIELD(TYPE value) {   \
        QMutexLocker locker(&lock);         \
        FIELD += value;                     \
    }                                       \

typedef uint8_t     u1;
typedef uint16_t    u2;
typedef uint32_t    u4;
typedef uint64_t    u8;
typedef int8_t      i1;
typedef int16_t     i2;
typedef int32_t     i4;
typedef int64_t     i8;
typedef float       f4;
typedef double      f8;
typedef long double f16;

extern u2 const UNLIMITED;
extern u2 const DEFAULT_PORT;
extern double const GALAXY_SIZE;

template< class T > T to_num(QString const& numStr, bool* convOk = 0);

template< class T, class E >
T parse_num(QDomElement const& numElem, T def, E exc = E()) {
    if (!numElem.isElement())
        return def;

    QDomNode const numNode = numElem.firstChild();

    if (!numNode.isText())
        exc();

    bool convOk;
    T num = to_num< T >(numNode.toText().nodeValue(), &convOk);

    if (!convOk)
        exc();

    return num;
}

template< class T, class E >
T parse_num(QDomElement const& numElem, E exc = E()) {
    if (!numElem.isElement())
        exc();

    QDomNode const numNode = numElem.firstChild();

    if (!numNode.isText())
        exc();

    bool convOk;
    T num = to_num< T >(numNode.toText().nodeValue(), &convOk);

    if (!convOk)
        exc();

    return num;
}

template< class E >
QString
parse_str(QDomElement const& textElem, QString const& def, E exc = E()) {
    if (textElem.isNull())
        return def;

    QDomNode textNode = textElem.firstChild();

    if (!textNode.isText())
        exc();

    return textNode.toText().nodeValue();
}

template< class E >
QString parse_str(QDomElement const& textElem, E exc = E()) {
    if (textElem.isNull())
        exc();

    QDomNode textNode = textElem.firstChild();

    if (!textNode.isText())
        exc();

    return textNode.toText().nodeValue();
}

template< class T > QString to_str(T value) {
    return QString::number(value);
}

QString to_str(QString value);

template< class T >
void to_xml(QDomNode& parent, QString const& name, T value) {
    QDomDocument doc = parent.ownerDocument();
    QDomElement elem = doc.createElement(name);
    QDomText text = doc.createTextNode(to_str(value));
    parent.appendChild(elem);
    elem.appendChild(text);
}

template< class T >
void to_xml(QDomNode& parent, QString const& name, T value, T def) {
    if (value == def)
        return;

    to_xml(parent, name, value);
}

#endif // ndef GLOBALS_HH_
